// ============================================================================
// Implementation file for Myscv
//
// Solution for CPSC 4780 Fall 2010 Group Project
// Fei Wang
// April 8, 2011
//
// Mysvc provide server stub functions
// ===========================================================================
#include "Mysvc.h"
#include "ServerSocket.h"
#include "ClientSocket.h"
#include <string>
#include <sstream>

#include <stdio.h> 
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <errno.h>
using namespace std;


/*Server stub functions*/
// ==========================================================================
// create a UDP Socket for Service
//===========================================================================
SVCXPRT * my_svcudp_create(int sock)
{
    string hostname = getlocalIP();
    ServerSocket * udpsocket = new ServerSocket(sock);
    int port = udpsocket -> getportnumber();
    SVCXPRT * transhandle = new SVCXPRT;
    transhandle -> port = port;
    transhandle -> address = hostname;
    transhandle -> svc_socket = udpsocket;
    return transhandle;
        
}
// ==========================================================================
// register service into portmapper
//===========================================================================
bool my_svc_register(SVCXPRT * transp,int prog)
{
    bool rev = true;
    ClientSocket * client_sock = new ClientSocket("localhost",10111);
    
 
    clntsock_send("register service -stub",client_sock);
    
    stringstream progstream;
    string s_prog = "";
    progstream << prog;
    progstream >> s_prog;
    
    clntsock_send(s_prog,client_sock);
    clntsock_send(transp-> address,client_sock);
    string s_port;
    stringstream portstream;
    
    portstream << transp -> port;
    portstream >> s_port;
    clntsock_send(s_port,client_sock);
    
    string feedback = "";
    clntsock_receive(feedback,client_sock);
    delete client_sock;
    
    if(feedback != "added")
         rev = false;
    return rev;

}
//========================================================================
// run the service
//========================================================================
void my_svc_run(SVCXPRT * transp,void (*dispatchfunc)(int ,ServerSocket *))
{
   try
   {
      ServerSocket * listerning_socket = transp -> svc_socket;
      while (true)
      {
	 ServerSocket * rpc_socket = new ServerSocket(0);
         listerning_socket->accept(*rpc_socket);       
         string st_rq_proc;
         svcsock_receive(st_rq_proc,rpc_socket);
         stringstream stream;
         int rq_proc = 0;
         stream << st_rq_proc;
         stream >> rq_proc;
         (*dispatchfunc)(rq_proc,rpc_socket);
      }
   }
   // Catch any Exceptions
   catch (SocketException& e)
   {
      std::cout << "Exception was caught:" << e.description() << "\nExiting.\n";
      cerr << "Error was in main!" << endl;
   }
}
//================================================================================================
//send reply to client
//================================================================================================
bool my_svc_sendreply(ServerSocket * rpc_socket,bool (*xdr_func)(XDR * ,char * ,int),char * result)
{
    bool rev = true;
    XDR res = "";
    rev = (*xdr_func)(&res,result,1);
    svcsock_send(res,rpc_socket);
    return rev;
    
}

//================================================================================================
//get argument from client side
//===============================================================================================
bool my_svc_getargs(ServerSocket * rpc_socket,bool (*xdr_func)(XDR *,char *,int),char * arguments)
{
    bool rev = true;
    XDR arg = "";
    svcsock_receive(arg,rpc_socket);
    rev = (*xdr_func)(&arg,arguments,2);

    return rev;
}

//================================================================================================
//get local hostname 
//================================================================================================
string getlocalhost()
{
  char hostname [128];
  gethostname(hostname,128);
  string rev(hostname);
  return rev;
}

//================================================================================================
//get IP address (eth0)
//================================================================================================
string getlocalIP(){
    string rev = "";
    struct ifaddrs *myaddrs, *ifa;
    void *in_addr;
    char buf[64];

    if(getifaddrs(&myaddrs) != 0)
        {
            perror("getifaddrs");
            exit(0);
        }

        for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
        {
            if (ifa->ifa_addr == NULL)
                continue;
            if (!(ifa->ifa_flags & IFF_UP))
                continue;
    
            switch (ifa->ifa_addr->sa_family)
            {
                case AF_INET:
                {
                    struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
                    in_addr = &s4->sin_addr;
                    break;
                }
   
                default:
                    continue;
            }
    
            if (inet_ntop(ifa->ifa_addr->sa_family, in_addr, buf, sizeof(buf)))
            {
                    string type = ifa->ifa_name;
                    if(type == "eth0")
                        rev = buf;
            }
        }
    //free pointers
    delete myaddrs;
    delete ifa;

    return rev;
}

//=======================================================================
// destructor to free memory
//=======================================================================
SVCXPRT::~SVCXPRT()
{
    delete svc_socket;
    svc_socket = NULL;
}
